package com.zenithmind.note.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.note.mapper.NoteMapper;
import com.zenithmind.note.mapper.NoteShareMapper;
import com.zenithmind.note.pojo.dto.NoteShareDTO;
import com.zenithmind.note.pojo.entity.Note;
import com.zenithmind.note.pojo.entity.NoteShare;
import com.zenithmind.note.pojo.query.NoteShareQuery;
import com.zenithmind.note.pojo.query.UserShareQuery;
import com.zenithmind.note.pojo.vo.NoteShareVO;
import com.zenithmind.note.pojo.vo.NoteVO;
import com.zenithmind.note.service.NoteService;
import com.zenithmind.note.service.NoteShareService;
import com.zenithmind.common.result.PageResult;
import com.zenithmind.common.result.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.zenithmind.common.exception.UnauthorizedException;
import com.zenithmind.common.annotation.DataCache;
import com.zenithmind.common.annotation.DataCacheEvict;
import com.zenithmind.common.constant.CacheConstants;
import com.zenithmind.common.security.SecurityUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 笔记分享服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class NoteShareServiceImpl extends ServiceImpl<NoteShareMapper, NoteShare> implements NoteShareService {
    
    private final NoteMapper noteMapper;
    private final NoteService noteService;
    
    @Value("${zenithmind.share.base-url:http://localhost:8080/api/zenithMind/share/view/}")
    private String shareBaseUrl;
    
    // 缓存相关常量
    private static final String CACHE_SHARE_PREFIX = "note:share";
    private static final String CACHE_USER_SHARE_PREFIX = "user:share";
    
    @Override
    public NoteShareVO createShare(NoteShareDTO noteShareDTO) {
        // 查询笔记是否存在
        Note note = noteMapper.selectById(noteShareDTO.getNoteId());
        if (note == null) {
            throw new RuntimeException("笔记不存在");
        }

        // 检查是否有权限分享：必须是自己的笔记
        String userId = SecurityUtils.getCurrentUserId();
        if (StringUtils.isBlank(userId)) {
            throw new UnauthorizedException("用户未登录");
        }
        
        if (!note.getUserId().equals(userId)) {
            throw new RuntimeException("无权分享该笔记");
        }
        
        // 生成分享码
        String shareCode = generateShareCode();
        
        // 创建分享记录
        NoteShare noteShare = new NoteShare();
        BeanUtils.copyProperties(noteShareDTO, noteShare);
        noteShare.setUserId(userId);
        noteShare.setShareCode(shareCode);
        noteShare.setShareCount(0);
        noteShare.setStatus(1); // 1-有效
        this.save(noteShare);
        
        // 转换为VO
        return buildShareVO(noteShare, note.getTitle());
    }
    
    @Override
    public NoteShareVO createShare(NoteShareDTO noteShareDTO, String userId) {
        // 查询笔记是否存在
        Note note = noteMapper.selectById(noteShareDTO.getNoteId());
        if (note == null) {
            throw new RuntimeException("笔记不存在");
        }

        // 检查是否有权限分享：必须是自己的笔记
        if (!note.getUserId().equals(userId)) {
            throw new RuntimeException("无权分享该笔记");
        }
        
        // 生成分享码
        String shareCode = generateShareCode();
        
        // 创建分享记录
        NoteShare noteShare = new NoteShare();
        BeanUtils.copyProperties(noteShareDTO, noteShare);
        noteShare.setUserId(userId);
        noteShare.setShareCode(shareCode);
        noteShare.setShareCount(0);
        noteShare.setStatus(1); // 1-有效
        this.save(noteShare);
        
        // 转换为VO
        return buildShareVO(noteShare, note.getTitle());
    }
    
    @Override
    public NoteShareVO getShareDetail(String shareId) {
        NoteShare noteShare = this.getById(shareId);
        if (noteShare == null) {
            throw new RuntimeException("分享不存在");
        }
        
        // 查询笔记标题
        Note note = noteMapper.selectById(noteShare.getNoteId());
        if (note == null) {
            throw new RuntimeException("笔记不存在");
        }
        
        return buildShareVO(noteShare, note.getTitle());
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public NoteVO getNoteByShareCode(String shareCode) {
        // 查询分享记录
        LambdaQueryWrapper<NoteShare> wrapper = Wrappers.<NoteShare>lambdaQuery()
                .eq(NoteShare::getShareCode, shareCode)
                .eq(NoteShare::getStatus, 1); // 1-有效
        NoteShare noteShare = this.getOne(wrapper);
        
        if (noteShare == null) {
            throw new RuntimeException("分享链接无效");
        }
        
        // 检查是否过期
        if (noteShare.getExpireTime() != null && noteShare.getExpireTime().isBefore(LocalDateTime.now())) {
            noteShare.setStatus(0); // 0-失效
            this.updateById(noteShare);
            throw new RuntimeException("分享链接已过期");
        }
        
        // 获取笔记详情 - 参数类型需要匹配
        NoteVO noteVO = noteService.getNoteDetail(noteShare.getNoteId(), null);
        
        // 增加访问次数
        incrementViewCount(shareCode);
        
        return noteVO;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> cancelShare(String shareId) {
        // 直接在方法内获取用户ID
        String userId = SecurityUtils.getCurrentUserId();
        if (StringUtils.isBlank(userId)) {
            throw new UnauthorizedException("用户未登录");
        }
        
        NoteShare noteShare = this.getById(shareId);
        if (noteShare == null) {
            throw new RuntimeException("分享不存在");
        }
        
        // 检查权限：必须是自己的分享
        if (!noteShare.getUserId().equals(userId)) {
            throw new RuntimeException("无权取消该分享");
        }
        
        // 设置分享状态为失效
        noteShare.setStatus(0); // 0-失效
        boolean updated = this.updateById(noteShare);
        return Result.success(updated);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> cancelShare(String shareId, String userId) {
        NoteShare noteShare = this.getById(shareId);
        if (noteShare == null) {
            throw new RuntimeException("分享不存在");
        }
        
        // 检查权限：必须是自己的分享
        if (!noteShare.getUserId().equals(userId)) {
            throw new RuntimeException("无权取消该分享");
        }
        
        // 设置分享状态为失效
        noteShare.setStatus(0); // 0-失效
        boolean updated = this.updateById(noteShare);
        return Result.success(updated);
    }
    
    @Override
    public PageResult<NoteShareVO> getUserShares(String userId, long current, long size) {
        // 分页查询用户的分享记录
        Page<NoteShare> page = new Page<>(current, size);
        LambdaQueryWrapper<NoteShare> wrapper = Wrappers.<NoteShare>lambdaQuery()
                .eq(NoteShare::getUserId, userId)
                .orderByDesc(NoteShare::getCreateTime);
        
        Page<NoteShare> sharePage = this.page(page, wrapper);
        
        if (sharePage.getRecords().isEmpty()) {
            return new PageResult<>(List.of(), sharePage.getTotal(), sharePage.getCurrent(), sharePage.getSize());
        }
        
        // 获取笔记ID
        List<String> noteIds = sharePage.getRecords().stream()
                .map(NoteShare::getNoteId)
                .collect(Collectors.toList());
        
        // 查询笔记标题
        LambdaQueryWrapper<Note> noteWrapper = Wrappers.<Note>lambdaQuery()
                .select(Note::getId, Note::getTitle)
                .in(Note::getId, noteIds);
        List<Note> notes = noteMapper.selectList(noteWrapper);
        
        // 构建标题映射
        java.util.Map<String, String> titleMap = notes.stream()
                .collect(Collectors.toMap(Note::getId, Note::getTitle));
        
        // 转换为VO
        List<NoteShareVO> shareVOs = sharePage.getRecords().stream()
                .map(share -> {
                    String title = titleMap.getOrDefault(share.getNoteId(), "未知标题");
                    return buildShareVO(share, title);
                })
                .collect(Collectors.toList());
        
        return new PageResult<>(shareVOs, sharePage.getTotal(), sharePage.getCurrent(), sharePage.getSize());
    }
    
    @Override
    public PageResult<NoteShareVO> getUserShares(long current, long size) {
        // 直接在方法内获取用户ID
        String userId = SecurityUtils.getCurrentUserId();
        if (StringUtils.isBlank(userId)) {
            throw new UnauthorizedException("用户未登录");
        }
        
        // 分页查询用户的分享记录
        Page<NoteShare> page = new Page<>(current, size);
        LambdaQueryWrapper<NoteShare> wrapper = Wrappers.<NoteShare>lambdaQuery()
                .eq(NoteShare::getUserId, userId)
                .orderByDesc(NoteShare::getCreateTime);
        
        Page<NoteShare> sharePage = this.page(page, wrapper);
        
        if (sharePage.getRecords().isEmpty()) {
            return new PageResult<>(List.of(), sharePage.getTotal(), sharePage.getCurrent(), sharePage.getSize());
        }
        
        // 获取笔记ID
        List<String> noteIds = sharePage.getRecords().stream()
                .map(NoteShare::getNoteId)
                .collect(Collectors.toList());
        
        // 查询笔记标题
        LambdaQueryWrapper<Note> noteWrapper = Wrappers.<Note>lambdaQuery()
                .select(Note::getId, Note::getTitle)
                .in(Note::getId, noteIds);
        List<Note> notes = noteMapper.selectList(noteWrapper);
        
        // 构建标题映射
        java.util.Map<String, String> titleMap = notes.stream()
                .collect(Collectors.toMap(Note::getId, Note::getTitle));
        
        // 转换为VO
        List<NoteShareVO> shareVOs = sharePage.getRecords().stream()
                .map(share -> {
                    String title = titleMap.getOrDefault(share.getNoteId(), "未知标题");
                    return buildShareVO(share, title);
                })
                .collect(Collectors.toList());
        
        return new PageResult<>(shareVOs, sharePage.getTotal(), sharePage.getCurrent(), sharePage.getSize());
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void incrementViewCount(String shareCode) {
        // 查询分享记录
        LambdaQueryWrapper<NoteShare> wrapper = Wrappers.<NoteShare>lambdaQuery()
                .eq(NoteShare::getShareCode, shareCode)
                .eq(NoteShare::getStatus, 1); // 1-有效
        NoteShare noteShare = this.getOne(wrapper);
        
        if (noteShare != null) {
            // 增加访问次数
            noteShare.setShareCount(noteShare.getShareCount() + 1);
            this.updateById(noteShare);
        }
    }
    
    /**
     * 生成唯一分享码
     */
    private String generateShareCode() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
    }
    
    /**
     * 构建分享VO
     */
    private NoteShareVO buildShareVO(NoteShare noteShare, String noteTitle) {
        NoteShareVO vo = new NoteShareVO();
        BeanUtils.copyProperties(noteShare, vo);
        vo.setNoteTitle(noteTitle);
        vo.setShareUrl(shareBaseUrl + noteShare.getShareCode());
        return vo;
    }

    /**
     * 后台管理-分页查询分享记录
     */
    @Override
    public PageResult<NoteShareVO> shareManagePage(NoteShareQuery query) {
        // 获取Page对象
        Page<NoteShare> page = query.toPage();
        
        // 构建查询条件
        LambdaQueryWrapper<NoteShare> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(query.getNoteId() != null && !query.getNoteId().isEmpty(), NoteShare::getNoteId, query.getNoteId())
              .eq(query.getUserId() != null, NoteShare::getUserId, query.getUserId())
              .eq(query.getStatus() != null, NoteShare::getStatus, query.getStatus())
              .like(StringUtils.isNotBlank(query.getShareCode()), NoteShare::getShareCode, query.getShareCode())
              .orderByDesc(NoteShare::getCreateTime);
        
        // 执行分页查询
        Page<NoteShare> sharePage = page(page, wrapper);
        
        // 转换为VO列表
        List<NoteShareVO> shareVOList = sharePage.getRecords().stream()
            .map(share -> {
                NoteShareVO shareVO = new NoteShareVO();
                BeanUtils.copyProperties(share, shareVO);
                return shareVO;
            })
            .collect(Collectors.toList());
        
        // 返回分页结果
        return PageResult.of(
            shareVOList,
            sharePage.getTotal(),
            sharePage.getCurrent(),
            sharePage.getSize()
        );
    }

    /**
     * 后台管理-获取分享详情
     */
    @Override
    @DataCache(prefix = CACHE_SHARE_PREFIX, key = "#shareId", expireTime = CacheConstants.TTL_SECONDS_DEFAULT)
    public NoteShareVO getShareById(String shareId) {
        NoteShare share = getById(shareId);
        if (share == null) {
            throw new RuntimeException("分享记录不存在");
        }
        
        // 转换为VO并返回
        NoteShareVO shareVO = new NoteShareVO();
        BeanUtils.copyProperties(share, shareVO);
        return shareVO;
    }

    /**
     * 后台管理-添加或修改分享记录
     */
    @Override
    @Transactional
    @DataCacheEvict(prefix = CACHE_SHARE_PREFIX, key = "#share.id")
    public NoteShareVO addOrUpdateShare(NoteShare share) {
        // 如果是修改操作
        if (StringUtils.isNotBlank(share.getId())) {
            NoteShare existingShare = getById(share.getId());
            if (existingShare == null) {
                throw new RuntimeException("分享记录不存在");
            }
            
            // 更新分享记录
            updateById(share);
        } else {
            // 新增分享记录
            // 生成分享码逻辑可在这里添加
            save(share);
        }
        
        // 返回更新后的分享信息
        NoteShareVO shareVO = new NoteShareVO();
        BeanUtils.copyProperties(getById(share.getId()), shareVO);
        return shareVO;
    }

    /**
     * 后台管理-批量删除分享记录
     */
    @Override
    @Transactional
    @DataCacheEvict(prefix = CACHE_SHARE_PREFIX, allEntries = true)
    public void deleteBatch(List<String> ids) {
        if (ids == null || ids.isEmpty()) {
            return;
        }
        
        log.info("批量删除分享记录：{}", ids);
        
        try {
            // 执行批量删除
            removeByIds(ids);
        } catch (Exception e) {
            log.error("批量删除分享记录失败：{}", e.getMessage(), e);
            throw new RuntimeException("批量删除分享记录失败", e);
        }
    }

    /**
     * 后台管理-批量更新分享状态
     */
    @Override
    @Transactional
    public void batchUpdateStatus(List<String> ids, Integer status) {
        if (ids == null || ids.isEmpty() || status == null) {
            return;
        }
        
        ids.forEach(id -> {
            NoteShare share = getById(id);
            if (share != null) {
                share.setStatus(status);
                updateById(share);
            }
        });
    }

    /**
     * 获取用户分享列表 - 使用查询对象
     *
     * @param query 查询对象
     * @return 分页结果
     */
    @Override
    @DataCache(prefix = CACHE_USER_SHARE_PREFIX, key = "#query.userId + ':' + #query.current + ':' + #query.size", 
              expireTime = CacheConstants.TTL_SECONDS_DEFAULT)
    public PageResult<NoteShareVO> getUserSharePage(UserShareQuery query) {
        String userId = SecurityUtils.getCurrentUserId();
        if (StringUtils.isBlank(userId)) {
            throw new UnauthorizedException("用户未登录");
        }
        
        // 创建分页对象
        Page<NoteShare> page = query.toPage();
        
        // 构建查询条件
        LambdaQueryWrapper<NoteShare> wrapper = Wrappers.<NoteShare>lambdaQuery()
                .eq(NoteShare::getUserId, userId)
                .eq(query.getStatus() != null, NoteShare::getStatus, query.getStatus())
                .like(StringUtils.isNotBlank(query.getShareCode()), NoteShare::getShareCode, query.getShareCode())
                .orderByDesc(NoteShare::getCreateTime);
        
        Page<NoteShare> sharePage = this.page(page, wrapper);
        
        if (sharePage.getRecords().isEmpty()) {
            return PageResult.of(List.of(), sharePage.getTotal(), sharePage.getCurrent(), sharePage.getSize());
        }
        
        // 获取笔记ID
        List<String> noteIds = sharePage.getRecords().stream()
                .map(NoteShare::getNoteId)
                .collect(Collectors.toList());
        
        // 查询笔记标题
        LambdaQueryWrapper<Note> noteWrapper = Wrappers.<Note>lambdaQuery()
                .select(Note::getId, Note::getTitle)
                .in(Note::getId, noteIds);
        
        // 如果有笔记标题查询条件，则添加
        if (StringUtils.isNotBlank(query.getNoteTitle())) {
            noteWrapper.like(Note::getTitle, query.getNoteTitle());
        }
        
        List<Note> notes = noteMapper.selectList(noteWrapper);
        
        // 构建标题映射
        java.util.Map<String, String> titleMap = notes.stream()
                .collect(Collectors.toMap(Note::getId, Note::getTitle));
        
        // 转换为VO，只包含笔记标题匹配的记录
        List<NoteShareVO> shareVOs = sharePage.getRecords().stream()
                .filter(share -> {
                    // 如果设置了笔记标题过滤，则只保留匹配的记录
                    if (StringUtils.isNotBlank(query.getNoteTitle())) {
                        return titleMap.containsKey(share.getNoteId());
                    }
                    return true;
                })
                .map(share -> {
                    String title = titleMap.getOrDefault(share.getNoteId(), "未知标题");
                    return buildShareVO(share, title);
                })
                .collect(Collectors.toList());
        
        // 重新计算总记录数，考虑笔记标题筛选后的结果
        long filteredTotal = shareVOs.size();
        if (StringUtils.isNotBlank(query.getNoteTitle()) && filteredTotal != sharePage.getTotal()) {
            return PageResult.of(shareVOs, filteredTotal, query.getCurrent().longValue(), query.getSize().longValue()); 
        } else {
            return PageResult.of(shareVOs, sharePage.getTotal(), sharePage.getCurrent(), sharePage.getSize());
        }
    }
} 